﻿// -----------------------------------------------------------------------
// <copyright file="MATLAPOper.cs" company="Fcis">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace LastVersionOfIpPackage.Operations
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Linq;
    using System.Text;
    using FreqDomainFuncts;
    using FrequencyDomain;
    using MathWorks.MATLAB.NET.Arrays;
    using MathWorks.MATLAB.NET.Utility;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class MATLAPOper 
    {
        /// <summary>
        /// static object of this class to use this without create object
        /// </summary>
        private static MATLAPOper matlapOper = new MATLAPOper();

        /// <summary>
        /// object of matlap class
        /// </summary>
        private FrequencyDomain newFreqDomain;

        /// <summary>
        /// object form Matlab class containg functions (EnhancementLocalStatistics ,EqualizationV2,SingleScaleRetinex,MultiScaleRetinex,Gauss1DFilter,LocalStatistics)
        /// </summary>
        private FreqDomainFuncts freqFunctins;

        /// <summary>
        /// buffer of input image
        /// </summary>
        private Color[,] bufferOfImage;

        /// <summary>
        /// real result from convert from spatial to frequence to special color
        /// </summary>
       private double[,] arrRealOfSpecialColor;

      /// <summary>
      /// imagian result from convert from spatial to frequence to special color
      /// </summary>
      private double[,] arrImagOfSpecialColor;

      /// <summary>
      /// real result from convert from spatial to frequence
      /// </summary>
      private double[,,] arrReal;

      /// <summary>
      /// imagian result from convert from spatial to frequence
      /// </summary>
      private double[,,] arrImag;

       /// <summary>
       /// result of magnitude of frequency signal in determine color
       /// </summary>
      private double[,] resultMagofSpecialColor;

      /// <summary>
      /// result of magnitude in each color
      /// </summary>
        private double[,,] resultMagForEachColor;

       /// <summary>
       /// red result
       /// </summary>
      private byte[,] selectedColorValue;

      /// <summary>
      /// Initializes a new instance of the <see cref="MATLAPOper"/> class.
      /// </summary>
      public MATLAPOper()
      {
          try
          {
              this.newFreqDomain = new FrequencyDomain();
              this.freqFunctins = new FreqDomainFuncts();
          }
          catch (Exception ex)
          {
              Logger.LogException(ex);
          }
      }

      /// <summary>
      /// Gets or sets the matlap oper.
      /// </summary>
      /// <value>
      /// The matlap oper.
      /// </value>
      public static MATLAPOper MatlapOper
      {
          get { return MATLAPOper.matlapOper; }
          set { MATLAPOper.matlapOper = value; }
      }

      /// <summary>
      /// Calcus the color of the magnitude TO detemine color.
      /// </summary>
      /// <param name="image">The image.</param>
      /// <param name="color">The color need magnitude of it.</param>
      /// <returns>
      /// new image of red
      /// </returns>
        public Bitmap CalcuMagnitudeTODetemineColor(Bitmap image, Enum_needed.ColorNeed color)
        {
            this.bufferOfImage = BufferOfImage.Buffer.GetBuffer(image);
            try
            {
                this.CalcuRealAndImagianToSpeficalColor(color);
            }
            catch
            {
                throw;
            }

            try
            {
                this.resultMagofSpecialColor = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1)];
                for (int i = 0; i < this.arrRealOfSpecialColor.GetLength(1); i++)
                {
                    for (int j = 0; j < this.arrRealOfSpecialColor.GetLength(0); j++)
                    {
                        this.resultMagofSpecialColor[j, i] = Math.Sqrt(Math.Pow(this.arrRealOfSpecialColor[j, i], 2) + Math.Pow(this.arrImagOfSpecialColor[j, i], 2));
                        this.resultMagofSpecialColor[j, i] = Math.Log(this.resultMagofSpecialColor[j, i] + 1);
                    }
                }
            }
            catch (Exception ex) 
            {
                Logger.LogException(ex);
                throw;
            }

            try
            {
                this.bufferOfImage = Normalize.Normalize11.Normalization(color, this.resultMagofSpecialColor);
                Bitmap resultImg = BufferOfImage.Buffer.GetImage(this.bufferOfImage);
                return resultImg;
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// convert the frequency domain to spatial domain.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <returns>
        /// new image in spatial domain
        /// </returns>
        public Bitmap ConvertToSpatialDomain(Bitmap image)
        {
            try
            {
                this.bufferOfImage = BufferOfImage.Buffer.GetBuffer(image);
                this.CalcuRealAndImagianToSpeficalColor(Enum_needed.ColorNeed.Red);
                MWArray returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] redSpatial = (double[,])returnedMatrix.ToArray();
                this.CalcuRealAndImagianToSpeficalColor(Enum_needed.ColorNeed.Green);
                returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] greenSpatial = (double[,])returnedMatrix.ToArray();
                this.CalcuRealAndImagianToSpeficalColor(Enum_needed.ColorNeed.Blue);
                returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] blueSpatial = (double[,])returnedMatrix.ToArray();
               for (int i = 0; i < blueSpatial.GetLength(1); i++)
                {
                    for (int j = 0; j < blueSpatial.GetLength(0); j++)
                    {
                        this.bufferOfImage[j, i] = Color.FromArgb((byte)redSpatial[j, i], (byte)greenSpatial[j, i], (byte)blueSpatial[j, i]);
                   }
                }

               return BufferOfImage.Buffer.GetImage(this.bufferOfImage);
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Converts to spatial domain v2.
        /// </summary>
        /// <param name="valuesReal">The values real.</param>
        /// <param name="valuesImg">The values img.</param>
        public void ConvertToSpatialDomainV2(double[,,] valuesReal, double[,,] valuesImg)
        {
            try
            {
                for (int i = 0; i < valuesImg.GetLength(1); i++)
                {
                    for (int j = 0; j < valuesImg.GetLength(0); j++)
                    {
                        this.arrImagOfSpecialColor[j, i] = valuesImg[j, i, 0];
                        this.arrRealOfSpecialColor[j, i] = valuesReal[j, i, 0];
                    }
                }

                MWArray returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] redSpatial = (double[,])returnedMatrix.ToArray();
                for (int i = 0; i < valuesImg.GetLength(1); i++)
                {
                    for (int j = 0; j < valuesImg.GetLength(0); j++)
                    {
                        this.arrImagOfSpecialColor[j, i] = valuesImg[j, i, 1];
                        this.arrRealOfSpecialColor[j, i] = valuesReal[j, i, 1];
                    }
                }

                returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] greenSpatial = (double[,])returnedMatrix.ToArray();
                for (int i = 0; i < valuesImg.GetLength(1); i++)
                {
                    for (int j = 0; j < valuesImg.GetLength(0); j++)
                    {
                        this.arrImagOfSpecialColor[j, i] = valuesImg[j, i, 2];
                        this.arrRealOfSpecialColor[j, i] = valuesReal[j, i, 2];
                    }
                }

                returnedMatrix = (MWArray)this.newFreqDomain.ToSpatialDomain((MWNumericArray)this.arrRealOfSpecialColor, (MWNumericArray)this.arrImagOfSpecialColor);
                double[,] blueSpatial = (double[,])returnedMatrix.ToArray();
                Bitmap newImg = new Bitmap(blueSpatial.GetLength(0), blueSpatial.GetLength(1));
                for (int i = 0; i < blueSpatial.GetLength(1); i++)
                {
                    for (int j = 0; j < blueSpatial.GetLength(0); j++)
                    {
                        valuesReal[j, i, 0] = redSpatial[j, i];
                        valuesReal[j, i, 1] = greenSpatial[j, i];
                        valuesReal[j, i, 2] = blueSpatial[j, i];
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Calcus the magnitude TO imag.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <returns>
        /// magnitude of this image
        /// </returns>
        public Bitmap CalcuMagnitudeTOImag(Bitmap image)
        {
            this.bufferOfImage = BufferOfImage.Buffer.GetBuffer(image);
            this.CalcuRealAndImagian();
            try
            {
                this.resultMagForEachColor = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), 3];
                for (int i = 0; i < this.arrReal.GetLength(1); i++)
                {
                    for (int j = 0; j < this.arrReal.GetLength(0); j++)
                    {
                        this.resultMagForEachColor[j, i, 0] = Math.Sqrt(Math.Pow(this.arrReal[j, i, 0], 2) + Math.Pow(this.arrImag[j, i, 0], 2));
                        this.resultMagForEachColor[j, i, 0] = Math.Log(this.resultMagForEachColor[j, i, 0] + 1);
                        this.resultMagForEachColor[j, i, 1] = Math.Sqrt(Math.Pow(this.arrReal[j, i, 1], 2) + Math.Pow(this.arrImag[j, i, 1], 2));
                        this.resultMagForEachColor[j, i, 1] = Math.Log(this.resultMagForEachColor[j, i, 1] + 1);
                        this.resultMagForEachColor[j, i, 2] = Math.Sqrt(Math.Pow(this.arrReal[j, i, 2], 2) + Math.Pow(this.arrImag[j, i, 2], 2));
                        this.resultMagForEachColor[j, i, 2] = Math.Log(this.resultMagForEachColor[j, i, 2] + 1);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }

           this.bufferOfImage = Normalize.Normalize11.Normalization(this.resultMagForEachColor);
           return BufferOfImage.Buffer.GetImage(this.bufferOfImage);
        }

        /// <summary>
        /// Calculte image of pass filter.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="typeOfPass">The type of pass.</param>
        /// <param name="typeOfMask">The type of mask.</param>
        /// <param name="d0">The d0.</param>
        /// <param name="order">The order.</param>
        /// <returns>
        /// new image.
        /// </returns>
        public Bitmap CalcuTOIMGPass(Bitmap image, Enum_needed.FilterType typeOfPass, Enum_needed.TypeOfMask typeOfMask, double d0, double order)
        {
            this.bufferOfImage = BufferOfImage.Buffer.GetBuffer(image);
            FilterMaskCalc newMask = new FilterMaskCalc();
            double[,] h = newMask.CalcFilterMaskToImage(typeOfPass, typeOfMask, this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), d0, order);
            this.CalcuRealAndImagian();
            double[,,] resultBeforeNormalizationReal = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), 3];
            double[,,] resultBeforeNormalizationImag = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), 3];
            for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
            {
                for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                {
                    resultBeforeNormalizationReal[j, i, 0] = this.arrReal[j, i, 0] * h[j, i];
                    resultBeforeNormalizationReal[j, i, 1] = this.arrReal[j, i, 1] * h[j, i];
                    resultBeforeNormalizationReal[j, i, 2] = this.arrReal[j, i, 2] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 0] = this.arrImag[j, i, 0] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 1] = this.arrImag[j, i, 1] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 2] = this.arrImag[j, i, 2] * h[j, i];
                }
            }

            this.ConvertToSpatialDomainV2(resultBeforeNormalizationReal, resultBeforeNormalizationImag);
            this.bufferOfImage = Normalize.Normalize11.Normalization(resultBeforeNormalizationReal);
            return BufferOfImage.Buffer.GetImage(this.bufferOfImage);
        }

        /// <summary>
        /// Calculte image of pass filter.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="typeOfPass">The type of pass.</param>
        /// <param name="typeOfMask">The type of mask.</param>
        /// <param name="d0">The d0.</param>
        /// <param name="order">The order.</param>
        /// <param name="uc">The uc point found in it noise.</param>
        /// <param name="vc">The vc point found in it noise.</param>
        /// <returns>
        /// modified image.
        /// </returns>
        public Bitmap CalcuTOIMGPass(Bitmap image, Enum_needed.FilterType typeOfPass, Enum_needed.TypeOfMask typeOfMask, double d0, double order, double uc, double vc)
        {
            this.bufferOfImage = BufferOfImage.Buffer.GetBuffer(image);
            double[,] h = FilterMaskCalc.FilterMaskCalc1.CalcFilterMaskToImage(typeOfPass, typeOfMask, this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), d0, uc, vc);
            this.CalcuRealAndImagian();
            double[,,] resultBeforeNormalizationReal = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), 3];
            double[,,] resultBeforeNormalizationImag = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), 3];
            for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
            {
                for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                {
                    resultBeforeNormalizationReal[j, i, 0] = this.arrReal[j, i, 0] * h[j, i];
                    resultBeforeNormalizationReal[j, i, 1] = this.arrReal[j, i, 1] * h[j, i];
                    resultBeforeNormalizationReal[j, i, 2] = this.arrReal[j, i, 2] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 0] = this.arrImag[j, i, 0] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 1] = this.arrImag[j, i, 1] * h[j, i];
                    resultBeforeNormalizationImag[j, i, 2] = this.arrImag[j, i, 2] * h[j, i];
                }
            }

            this.ConvertToSpatialDomainV2(resultBeforeNormalizationReal, resultBeforeNormalizationImag);
           this.bufferOfImage = Normalize.Normalize11.Normalization(resultBeforeNormalizationReal);
            return BufferOfImage.Buffer.GetImage(this.bufferOfImage);
        }

        /// <summary>
        /// Locals  histogram equalization.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="maskSize">Size of the mask.</param>
        /// <returns>The new image </returns>
        public Bitmap LocalHistogramEqualization(Bitmap image, int maskSize)
        {
            try
            {
                Bitmap newImg = new Bitmap(image);
                this.bufferOfImage = BufferOfImage.Buffer.GetBuffer(image);
               double[,] valueOfImage = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1)];
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        valueOfImage[j, i] = (double)this.bufferOfImage[j, i].R;
                    }
                }

                MWArray[] returnedMatrix = new MWArray[2];
                returnedMatrix[0] = (MWArray)this.freqFunctins.EqualizationV2((MWNumericArray)valueOfImage, maskSize);
                byte[,]returned = (byte[,])returnedMatrix[0].ToArray();
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        Color c = Color.FromArgb((int)returned[j, i], (int)returned[j, i], (int)returned[j, i]);
                        newImg.SetPixel(j, i, c);
                    }
                }

                return newImg;                
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Locals statistics.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="maskSize">Size of the mask.</param>
        /// <param name="e">The e.</param>
        /// <param name="k0">The k0.</param>
        /// <param name="k1">The k1.</param>
        /// <param name="k2">The k2.</param>
        /// <returns>the new image</returns>
        public Bitmap LocalStatistics(Bitmap image, int maskSize, int e, double k0, double k1, double k2)
        {
            try
            {
                this.bufferOfImage = BufferOfImage.Buffer.GetBuffer(image);
                double[,] valueOfImage = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1)];
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        valueOfImage[j, i] = (double)this.bufferOfImage[j, i].R;                        
                    }
                }

                Bitmap newImg = new Bitmap(this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1));
                MWArray[] returnedMatrix = new MWArray[2];
                returnedMatrix[0] = (MWArray)this.freqFunctins.EnhancementLocalStatistics((MWNumericArray)valueOfImage, maskSize, e, k0, k1, k2);
                byte[,]returned = (byte[,])returnedMatrix[0].ToArray();
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        Color c = Color.FromArgb((int)returned[j, i], (int)returned[j, i], (int)returned[j, i]);
                        newImg.SetPixel(j, i, c);
                    }
                }

                return newImg;
            }
            catch (Exception ex)
            {
                LastVersionOfIpPackage.Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Calcus the real and imagian of special color.
        /// </summary>
        /// <param name="color">The color need magnitude of it.</param>
        private void CalcuRealAndImagianToSpeficalColor(Enum_needed.ColorNeed color)
        {
            try
            {
                this.selectedColorValue = new byte[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1)];
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        if (color == Enum_needed.ColorNeed.Red)
                        {
                            this.selectedColorValue[j, i] = this.bufferOfImage[j, i].R;
                        }
                        else if (color == Enum_needed.ColorNeed.Green)
                        {
                            this.selectedColorValue[j, i] = this.bufferOfImage[j, i].G;
                        }
                        else if (color == Enum_needed.ColorNeed.Blue)
                        {
                            this.selectedColorValue[j, i] = this.bufferOfImage[j, i].B;
                        }
                    }
                }

                MWArray[] returnedMatrix = (MWArray[])this.newFreqDomain.ToFrequencyDomain(2, (MWNumericArray)this.selectedColorValue);
                this.arrRealOfSpecialColor = (double[,])returnedMatrix[0].ToArray();
                this.arrImagOfSpecialColor = (double[,])returnedMatrix[1].ToArray();
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }

        /// <summary>
        /// Calcus the real and imagian of iamge.
        /// </summary>
        private void CalcuRealAndImagian()
        {
            try
            {
                double[,] valueOfImage = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1)];
                this.arrImag = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), 3];
                this.arrReal = new double[this.bufferOfImage.GetLength(0), this.bufferOfImage.GetLength(1), 3];
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        valueOfImage[j, i] = (double)this.bufferOfImage[j, i].R;
                    }
                }

                MWArray[] returnedMatrix = (MWArray[])this.newFreqDomain.ToFrequencyDomain(2, (MWNumericArray)valueOfImage);
                this.arrRealOfSpecialColor = (double[,])returnedMatrix[0].ToArray();
                this.arrImagOfSpecialColor = (double[,])returnedMatrix[1].ToArray();
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        this.arrReal[j, i, 0] = this.arrRealOfSpecialColor[j, i];
                        this.arrImag[j, i, 0] = this.arrImagOfSpecialColor[j, i];
                        valueOfImage[j, i] = this.bufferOfImage[j, i].G;
                        ////valueOfImage[j, i] = this.BufferOfImage[j, i].B;
                    }
                }

                returnedMatrix = (MWArray[])this.newFreqDomain.ToFrequencyDomain(2, (MWNumericArray)valueOfImage);
                this.arrRealOfSpecialColor = (double[,])returnedMatrix[0].ToArray();
                this.arrImagOfSpecialColor = (double[,])returnedMatrix[1].ToArray();
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        this.arrReal[j, i, 1] = this.arrRealOfSpecialColor[j, i];
                        this.arrImag[j, i, 1] = this.arrImagOfSpecialColor[j, i];
                        valueOfImage[j, i] = this.bufferOfImage[j, i].B;
                    }
                }

                returnedMatrix = (MWArray[])this.newFreqDomain.ToFrequencyDomain(2, (MWNumericArray)valueOfImage);
                this.arrRealOfSpecialColor = (double[,])returnedMatrix[0].ToArray();
                this.arrImagOfSpecialColor = (double[,])returnedMatrix[1].ToArray();
                for (int i = 0; i < this.bufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.bufferOfImage.GetLength(0); j++)
                    {
                        this.arrReal[j, i, 2] = this.arrRealOfSpecialColor[j, i];
                        this.arrImag[j, i, 2] = this.arrImagOfSpecialColor[j, i];
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw;
            }
        }
    }
}
